﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using l1cs.server.templates;
using l1cs.server.serverpackets;
using System.Threading;
using l1cs.server.datatables;
using l1cs.server.model.skill;

namespace l1cs.server.model.Instance
{
    public class L1EffectInstance : L1NpcInstance
    {
        private static Logger _log = Logger.getLogger( typeof( L1EffectInstance ).FullName );

        private Timer _effectFuture;
        private const int FW_DAMAGE_INTERVAL = 1000;
        private const int CUBE_INTERVAL = 500; // キューブ範囲内に居るキャラクターをチェックする間隔
        private const int CUBE_TIME = 8000; // 効果時間8秒?

        public L1EffectInstance( L1Npc template )
            : base( template )
        {
            int npcId = getNpcTemplate().get_npcId();
            if ( npcId == 81157 )
            { // FW
                //GeneralThreadPool.getInstance().schedule( new FwDamageTimer( this ), 0 );
                _effectFuture = new Timer( new TimerCallback( FwDamageTimerSub ), null, 0, Timeout.Infinite );
            }
            else if ( npcId == 80149 // キューブ[イグニション]
                  || npcId == 80150 // キューブ[クエイク]
                  || npcId == 80151 // キューブ[ショック]
                  || npcId == 80152 )
            { // キューブ[バランス]
                // GeneralThreadPool.getInstance().schedule( new CubeTimer( this ), 0 );
                _effectFuture = new Timer( new TimerCallback( CubeTimerSub ), null, 0, Timeout.Infinite );
            }
        }

        override public void onAction( L1PcInstance pc ) { }

        override public void deleteMe()
        {
            _destroyed = true;
            if ( getInventory() != null )
            {
                getInventory().clearItems();
            }
            allTargetClear();
            _master = null;
            L1World.getInstance().removeVisibleObject( this );
            L1World.getInstance().removeObject( this );
            foreach ( L1PcInstance pc in L1World.getInstance().getRecognizePlayer( this ) )
            {
                pc.removeKnownObject( this );
                pc.sendPackets( new S_RemoveObject( this ) );
            }
            removeAllKnownObjects();
        }

        //class FwDamageTimer implements Runnable {
        private L1EffectInstance _effect;

        //public FwDamageTimer(L1EffectInstance effect) {
        //    _effect = effect;
        //}

        //@Override
        public void FwDamageTimerSub( object state )
        {
            while ( !_destroyed )
            {
                foreach ( L1Object objects in L1World.getInstance().getVisibleObjects( _effect, 0 ) )
                {
                    if ( objects is L1PcInstance )
                    {
                        L1PcInstance pc = (L1PcInstance)objects;
                        if ( pc.isDead() )
                        {
                            continue;
                        }
                        if ( pc.getZoneType() == 1 )
                        {
                            bool isNowWar = false;
                            int castleId = L1CastleLocation
                                    .getCastleIdByArea( pc );
                            if ( castleId > 0 )
                            {
                                isNowWar = WarTimeController.getInstance().isNowWar( castleId );
                            }
                            if ( !isNowWar )
                            {
                                continue;
                            }
                        }
                        L1Magic magic = new L1Magic( _effect, pc );
                        int damage = magic.calcPcFireWallDamage();
                        if ( damage == 0 )
                        {
                            continue;
                        }
                        pc.sendPackets( new S_DoActionGFX( pc.getId(),
                                ActionCodes.ACTION_Damage ) );
                        pc.broadcastPacket( new S_DoActionGFX( pc.getId(),
                                ActionCodes.ACTION_Damage ) );
                        pc.receiveDamage( _effect, damage, false );
                    }
                    else if ( objects is L1MonsterInstance )
                    {
                        L1MonsterInstance mob = (L1MonsterInstance)objects;
                        if ( mob.isDead() )
                        {
                            continue;
                        }
                        L1Magic magic = new L1Magic( _effect, mob );
                        int damage = magic.calcNpcFireWallDamage();
                        if ( damage == 0 )
                        {
                            continue;
                        }
                        mob.broadcastPacket( new S_DoActionGFX( mob.getId(),
                                ActionCodes.ACTION_Damage ) );
                        mob.receiveDamage( _effect, damage );
                    }
                }
                Thread.Sleep( FW_DAMAGE_INTERVAL );

            }
        }
        //}

        //class CubeTimer implements Runnable {
        //	private L1EffectInstance _effect;

        //	public CubeTimer(L1EffectInstance effect) {
        //		_effect = effect;
        //	}

        //	@Override
        public void CubeTimerSub( object state )
        {
            while ( !_destroyed )
            {
                foreach ( L1Object objects in L1World.getInstance().getVisibleObjects( _effect, 3 ) )
                {
                    if ( objects is L1PcInstance )
                    {
                        L1PcInstance pc = (L1PcInstance)objects;
                        if ( pc.isDead() )
                        {
                            continue;
                        }
                        L1PcInstance user = getUser(); // Cube使用者
                        if ( pc.getId() == user.getId() )
                        {
                            cubeToAlly( pc, _effect );
                            continue;
                        }
                        if ( pc.getClanid() != 0
                                && user.getClanid() == pc.getClanid() )
                        {
                            cubeToAlly( pc, _effect );
                            continue;
                        }
                        if ( pc.isInParty()
                                && pc.getParty().isMember( user ) )
                        {
                            cubeToAlly( pc, _effect );
                            continue;
                        }
                        if ( pc.getZoneType() == 1 )
                        { // セーフティーゾーンでは戦争中を除き敵には無効
                            bool isNowWar = false;
                            int castleId = L1CastleLocation
                                    .getCastleIdByArea( pc );
                            if ( castleId > 0 )
                            {
                                isNowWar = WarTimeController.getInstance()
                                        .isNowWar( castleId );
                            }
                            if ( !isNowWar )
                            {
                                continue;
                            }
                            cubeToEnemy( pc, _effect );
                        }
                        else
                        {
                            cubeToEnemy( pc, _effect );
                        }
                    }
                    else if ( objects is L1MonsterInstance )
                    {
                        L1MonsterInstance mob = (L1MonsterInstance)objects;
                        if ( mob.isDead() )
                        {
                            continue;
                        }
                        cubeToEnemy( mob, _effect );
                    }
                }
                Thread.Sleep( CUBE_INTERVAL );
            }
        }
        //}

        private void cubeToAlly( L1Character cha, L1Character effect )
        {
            int npcId = getNpcTemplate().get_npcId();
            int castGfx = SkillsTable.getInstance().getTemplate( getSkillId() ).getCastGfx();
            L1PcInstance pc = null;

            if ( npcId == 80149 )
            { // キューブ[イグニション]
                if ( !cha.hasSkillEffect( L1SkillId.STATUS_CUBE_IGNITION_TO_ALLY ) )
                {
                    cha.addFire( 30 );
                    if ( cha is L1PcInstance )
                    {
                        pc = (L1PcInstance)cha;
                        pc.sendPackets( new S_OwnCharAttrDef( pc ) );
                        pc.sendPackets( new S_SkillSound( pc.getId(), castGfx ) );
                    }
                    cha.broadcastPacket( new S_SkillSound( cha.getId(), castGfx ) );
                    cha.setSkillEffect( L1SkillId.STATUS_CUBE_IGNITION_TO_ALLY, CUBE_TIME );
                }
            }
            else if ( npcId == 80150 )
            { // キューブ[クエイク]
                if ( !cha.hasSkillEffect( L1SkillId.STATUS_CUBE_QUAKE_TO_ALLY ) )
                {
                    cha.addEarth( 30 );
                    if ( cha is L1PcInstance )
                    {
                        pc = (L1PcInstance)cha;
                        pc.sendPackets( new S_OwnCharAttrDef( pc ) );
                        pc.sendPackets( new S_SkillSound( pc.getId(), castGfx ) );
                    }
                    cha.broadcastPacket( new S_SkillSound( cha.getId(), castGfx ) );
                    cha.setSkillEffect( L1SkillId.STATUS_CUBE_QUAKE_TO_ALLY, CUBE_TIME );
                }
            }
            else if ( npcId == 80151 )
            { // キューブ[ショック]
                if ( !cha.hasSkillEffect( L1SkillId.STATUS_CUBE_SHOCK_TO_ALLY ) )
                {
                    cha.addWind( 30 );
                    if ( cha is L1PcInstance )
                    {
                        pc = (L1PcInstance)cha;
                        pc.sendPackets( new S_OwnCharAttrDef( pc ) );
                        pc.sendPackets( new S_SkillSound( pc.getId(), castGfx ) );
                    }
                    cha.broadcastPacket( new S_SkillSound( cha.getId(), castGfx ) );
                    cha.setSkillEffect( L1SkillId.STATUS_CUBE_SHOCK_TO_ALLY, CUBE_TIME );
                }
            }
            else if ( npcId == 80152 )
            { // キューブ[バランス]
                if ( !cha.hasSkillEffect( L1SkillId.STATUS_CUBE_BALANCE ) )
                {
                    if ( cha is L1PcInstance )
                    {
                        pc = (L1PcInstance)cha;
                        pc.sendPackets( new S_SkillSound( pc.getId(), castGfx ) );
                    }
                    cha.broadcastPacket( new S_SkillSound( cha.getId(), castGfx ) );
                    cha.setSkillEffect( L1SkillId.STATUS_CUBE_BALANCE, CUBE_TIME );
                    L1Cube cube = new L1Cube( effect, cha, L1SkillId.STATUS_CUBE_BALANCE );
                    cube.begin();
                }
            }
        }

        private void cubeToEnemy( L1Character cha, L1Character effect )
        {
            int npcId = getNpcTemplate().get_npcId();
            int castGfx2 = SkillsTable.getInstance().getTemplate( getSkillId() )
                    .getCastGfx2();
            L1PcInstance pc = null;
            if ( npcId == 80149 )
            { // キューブ[イグニション]
                if ( !cha.hasSkillEffect( L1SkillId.STATUS_CUBE_IGNITION_TO_ENEMY ) )
                {
                    if ( cha is L1PcInstance )
                    {
                        pc = (L1PcInstance)cha;
                        pc.sendPackets( new S_SkillSound( pc.getId(), castGfx2 ) );
                    }
                    cha.broadcastPacket( new S_SkillSound( cha.getId(), castGfx2 ) );
                    cha.setSkillEffect( L1SkillId.STATUS_CUBE_IGNITION_TO_ENEMY, CUBE_TIME );
                    L1Cube cube = new L1Cube( effect, cha, L1SkillId.STATUS_CUBE_IGNITION_TO_ENEMY );
                    cube.begin();
                }
            }
            else if ( npcId == 80150 )
            { // キューブ[クエイク]
                if ( !cha.hasSkillEffect( L1SkillId.STATUS_CUBE_QUAKE_TO_ENEMY ) )
                {
                    if ( cha is L1PcInstance )
                    {
                        pc = (L1PcInstance)cha;
                        pc.sendPackets( new S_SkillSound( pc.getId(), castGfx2 ) );
                    }
                    cha.broadcastPacket( new S_SkillSound( cha.getId(), castGfx2 ) );
                    cha.setSkillEffect( L1SkillId.STATUS_CUBE_QUAKE_TO_ENEMY, CUBE_TIME );
                    L1Cube cube = new L1Cube( effect, cha, L1SkillId.STATUS_CUBE_QUAKE_TO_ENEMY );
                    cube.begin();
                }
            }
            else if ( npcId == 80151 )
            { // キューブ[ショック]
                if ( !cha.hasSkillEffect( L1SkillId.STATUS_CUBE_SHOCK_TO_ENEMY ) )
                {
                    if ( cha is L1PcInstance )
                    {
                        pc = (L1PcInstance)cha;
                        pc.sendPackets( new S_SkillSound( pc.getId(), castGfx2 ) );
                    }
                    cha.broadcastPacket( new S_SkillSound( cha.getId(), castGfx2 ) );
                    cha.setSkillEffect( L1SkillId.STATUS_CUBE_SHOCK_TO_ENEMY, CUBE_TIME );
                    L1Cube cube = new L1Cube( effect, cha, L1SkillId.STATUS_CUBE_SHOCK_TO_ENEMY );
                    cube.begin();
                }
            }
            else if ( npcId == 80152 )
            { // キューブ[バランス]
                if ( !cha.hasSkillEffect( L1SkillId.STATUS_CUBE_BALANCE ) )
                {
                    if ( cha is L1PcInstance )
                    {
                        pc = (L1PcInstance)cha;
                        pc.sendPackets( new S_SkillSound( pc.getId(), castGfx2 ) );
                    }
                    cha.broadcastPacket( new S_SkillSound( cha.getId(), castGfx2 ) );
                    cha.setSkillEffect( L1SkillId.STATUS_CUBE_BALANCE, CUBE_TIME );
                    L1Cube cube = new L1Cube( effect, cha, L1SkillId.STATUS_CUBE_BALANCE );
                    cube.begin();
                }
            }
        }

        private L1PcInstance _pc;

        public void setUser( L1PcInstance pc )
        {
            _pc = pc;
        }

        public L1PcInstance getUser()
        {
            return _pc;
        }

        private int _skillId;

        public void setSkillId( int i )
        {
            _skillId = i;
        }

        public int getSkillId()
        {
            return _skillId;
        }
    }
}
